﻿using PLCS.Application.Contracts.StationApp.Dtos;
using PLCS.Application.Contracts.TrayApp;
using PLCS.Application.Contracts.TrayApp.Dtos;
using PLCS.Domain.Shared.Stations;
using PLCS.Domain.Stations;
using PLCS.Domain.Trays;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.ObjectMapping;

namespace PLCS.Application.TrayApp;

public class TrayAppService : CrudAppService<Tray, TrayDto, Guid, PagedResultRequestDto, TrayEditDto>, ITrayAppService
{
    private readonly IRepository<Tray, Guid> _trayRepository;
    private readonly IStationRepository _stationRepository;

    public TrayAppService(IRepository<Tray, Guid> trayRepository, IStationRepository stationRepository) : base(trayRepository)
    {
        this._trayRepository = trayRepository;
        this._stationRepository = stationRepository;
    }

    public async Task DisassociateAsync(TrayDto tray)
    {
        var station = await _stationRepository.FindAsync(x => x.Id == tray.StationId);
        station.RemoveTray();
        if (station.TrayCount != 0 && (station.StationType == StationType.栈工位 || station.StationType == StationType.队列工位))
        {
            station.TrayCount--;
        }
        await _stationRepository.UpdateAsync(station);
    }

    //public async Task<IEnumerable<TrayDto>> GetListAsync()
    //{
    //    var query = await _trayRepository.GetQueryableAsync();
    //    var entities = query.Include(x => x.Station);
    //    var dtos = ObjectMapper.Map<IEnumerable<Tray>, IEnumerable<TrayDto>>(entities);
    //    foreach (var dto in dtos)
    //    {
    //        dto.StaNum = entities.Single(x => x.Id == dto.Id).Station?.StaNum;
    //    }
    //    return dtos;
    //}

    public async Task<PagedResultDto<TrayDto>> GetListBySearchAsync(PagedResultRequestDto input, string? trayType, string? trayNo)
    {
        await CheckGetListPolicyAsync();

        var query = await ReadOnlyRepository.GetQueryableAsync();
        query = query.Include(x => x.Station);
        query = query.WhereIf(!string.IsNullOrEmpty(trayType), x => x.TrayType == (TrayType)Enum.Parse(typeof(TrayType), trayType))
            .WhereIf(!string.IsNullOrEmpty(trayNo), x => x.TrayNo == trayNo);
        var totalCount = await AsyncExecuter.CountAsync(query);

        query = ApplyPaging(query, input);

        var entities = await AsyncExecuter.ToListAsync(query);
        var entityDtos = await MapToGetListOutputDtosAsync(entities);

        return new PagedResultDto<TrayDto>(
            totalCount,
            entityDtos
        );
    }

    public async Task<TrayDto?> GetTrayByNoAsync(string trayNo)
    {
        var tray = await _trayRepository.FindAsync(x => x.TrayNo == trayNo);
        if (tray == null)
            return null;
        return ObjectMapper.Map<Tray, TrayDto>(tray);
    }

    public async Task TrayBindAsync(TrayDto tray)
    {
        var cache = await _trayRepository.GetAsync(tray.Id);
        if (cache.StationId != null)
            throw new ArgumentException("托盘正在其他工位上，请先解绑");

        var station = await _stationRepository.GetStationByNumAsync(tray.StaNum) ?? throw new ArgumentException($"'{tray.StaNum}'为空，请确认"); ;
        station.AddTray(cache);
        await _stationRepository.UpdateAsync(station);
    }

    public async Task UpdateAsync(TrayEditDto input)
    {
        var entity = await GetEntityByIdAsync(input.Id);
        await MapToEntityAsync(input, entity);
        await Repository.UpdateAsync(entity, autoSave: true);
    }

    public async Task CreateListAsync(IEnumerable<TrayEditDto> trays)
    {
        var entities = ObjectMapper.Map<IEnumerable<TrayEditDto>, IEnumerable<Tray>>(trays);
        await _trayRepository.InsertManyAsync(entities);
    }
}